package com.example.jobback.websocket.intercept;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.example.jobback.config.AuthConfig;
import com.example.jobback.po.Manager;
import com.example.jobback.po.Recruiter;
import com.example.jobback.po.Seeker;
import com.example.jobback.util.CACHEUtil;
import com.example.jobback.util.JWTUtil;
import com.example.jobback.util.SecureEncryptionUtil;
import jakarta.websocket.HandshakeResponse;
import jakarta.websocket.server.HandshakeRequest;
import jakarta.websocket.server.ServerEndpointConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import static com.example.jobback.util.RedisConstants.*;

@Component
public class WebSocketHandshakeInterceptor {

    @Value("${ws.role.seeker}") private String seekerRole;
    @Value("${ws.role.recruiter}") private String recruiterRole;
    @Value("${ws.role.manager}") private String managerRole;

    private final CACHEUtil cacheUtil;
    private final AuthConfig authConfig;

    public WebSocketHandshakeInterceptor(AuthConfig authConfig, CACHEUtil cacheUtil) {
        this.authConfig = authConfig;
        this.cacheUtil = cacheUtil;
    }

    public void handleHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) throws Exception {
        try{
            String path = request.getRequestURI().getPath();
            String role = extractRoleFromPath(path, "/message/");
            // 统一获取Token
            String token = getAuthToken(request);
            // 根据角色进行验证
            if (seekerRole.equals(role)) {
                validateUser(token,
                        authConfig.getJwtSeekerSecret(),
                        SEEKER_KEY,
                        Seeker.class,sec,role);
            } else if (recruiterRole.equals(role)) {
                validateUser(token,
                        authConfig.getJwtRecruiterSecret(),
                        RECRUITER_KEY,
                        Recruiter.class,sec,role);
            } else if (managerRole.equals(role)) {
                validateUser(token,
                        authConfig.getJwtManagerSecret(),
                        MANAGER_KEY,
                        Manager.class,sec,role);
            } else {
                throw new IllegalArgumentException("CLIENT_ERROR:允许的角色只包括 "
                        + String.join(", ", seekerRole, recruiterRole, managerRole));
            }
        }catch (Exception e){
            sec.getUserProperties().put("handshakeError", e.getMessage());
        }
    }
    
    /**
     * @Description: 验证token方法
     * @param token
     * @param jwtSecret
     * @param redisKeyPrefix
     * @param userType
     * @param sec
     * @param role 
     * @return void
     * @Author lhb
     * @CreateTime 2025/5/29 22:22
     */
    private <T> void validateUser(String token,
                                  String jwtSecret,
                                  String redisKeyPrefix,
                                  Class<T> userType,
                                  ServerEndpointConfig sec,
                                  String role) throws Exception {
        // 1. 验证Token有效性
        String userIdentity = JWTUtil.checkToken(token, jwtSecret);
        if (StrUtil.isBlank(userIdentity)) {
            throw new IllegalArgumentException("CLIENT_ERROR:token认证失败");
        }
        // 2. 解密用户ID
        String userIdStr = SecureEncryptionUtil.decrypt(userIdentity, authConfig.getJwtIdSecret());

        // 3. 从Redis获取用户数据
        String redisKey = redisKeyPrefix + userIdStr;
        Map<Object, Object> userMap = cacheUtil.getHash(redisKey);


        // 4. 验证登录状态
        String redisToken = (String) userMap.get("token");
        String userJson = (String) userMap.get("user");
        T user = JSON.parseObject(userJson, userType);

        if (redisToken == null || user == null) {
            throw new IllegalArgumentException("CLIENT_ERROR:用户还没登录");
        }

        // 5. 验证Token一致性（去掉Bearer前缀）
        if (!redisToken.equals(extractRawToken(token))) {
            throw new IllegalArgumentException("CLIENT_ERROR:用户已在另一台设备登录");
        }
        sec.getUserProperties().put("userIdStr", userIdStr);
        sec.getUserProperties().put("role", role);
    }

    /**
     * @Description: 从请求中获取token
     * @param request 
     * @return String
     * @Author lhb
     * @CreateTime 2025/5/29 22:22
     */
    private String getAuthToken(HandshakeRequest request) {
        String requestURI = String.valueOf(request.getRequestURI());
        String token = extractTokenFromURI(requestURI);
        if (token == null || token.isEmpty()) {
            throw new IllegalArgumentException("CLIENT_ERROR:token缺失");
        }
        // 如果 token 没有 Bearer 前缀，手动添加
        if (!token.startsWith("Bearer ")) {
            token = "Bearer " + token;
        }
        return token;
    }

    /**
     * @Description: 解析 URI 字符串，提取 token 参数：
     * @param uri
     * @return String
     * @Author lhb
     * @CreateTime 2025/7/4 21:28
     */
    private String extractTokenFromURI(String uri) {
        try {
            java.net.URI uriObj = new java.net.URI(uri);
            String query = uriObj.getQuery();
            if (query != null) {
                Map<String, String> params = parseQueryString(query);
                return params.get("token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description: 将查询字符串解析为键值对 Map
     * @param query
     * @return Map<String,String>
     * @Author lhb
     * @CreateTime 2025/7/4 21:29
     */
    private Map<String, String> parseQueryString(String query) {
        Map<String, String> result = new HashMap<>();
        if (query == null || query.isEmpty()) {
            return result;
        }
        String[] pairs = query.split("&");
        for (String pair : pairs) {
            int idx = pair.indexOf("=");
            String key = idx > 0 ? pair.substring(0, idx) : pair;
            String value = idx > 0 && pair.length() > idx + 1 ? pair.substring(idx + 1) : "";
            result.put(key, value);
        }
        return result;
    }


    /**
     * @Description: 去除Bearer 前缀
     * @param bearerToken
     * @return String
     * @Author lhb
     * @CreateTime 2025/5/29 22:23
     */
    private String extractRawToken(String bearerToken) {
        if (bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return bearerToken;
    }

    /**
     * @Description: 在path中获取role字段
     * @param path
     * @param prefix 
     * @return String
     * @Author lhb
     * @CreateTime 2025/5/29 22:28
     */
    private String extractRoleFromPath(String path, String prefix) {
        return path.startsWith(prefix) ?
                path.substring(prefix.length()).split("/")[0] :
                null;
    }
}